/**
 * 
 */
package openbee;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import openbee.enums.BroadcastType;
import openbee.enums.PANidType;
import openbee.enums.ProtectedRegister;
import openbee.enums.Register;

/**
 * @author Maczek
 * 
 */
public class ModuleControl implements IModuleControl, ResponseListener {

	private final static ArrayList<String> DEVICES = new ArrayList<String>() {
		{
			add("MED");
			add("FFD");
			add("SED");
		}
	};

	private Communication communication;
	private Coordinator coordinator;
	private CommandArguments result;
	private List<String> list;

	public ModuleControl(Communication communication) {
		this.setCommunication(communication);
		communication.addMoodListener(this);
		setCoordinator(new Coordinator());
	}

	@Override
	public void moodReceived(ResponseEvent event) {
		// TODO Auto-generated method stub
		result = event.get_commandArguemnts();

		if (result.isNewNode()) {
			for (String device : DEVICES) {

				list = Arrays.asList(result.get_prompt().split("\r\n"));
				for (String resp : list) {
					if (resp.contains(device))
						addNode(resp.split(":")[0],
								resp.split(":")[1].split(",")[0]);
				}
			}
		}
	}

	private void addNode(String type, String uid64) {
		// TODO Auto-generated method stub

		Node node;
		if (type.equals("MED") || type.equals("SED")) {
			node = new EndDevice();
			node.setEui64(uid64);
			getCoordinator().addNode(node);
		} else if (type.equals("FFD")) {
			node = new Router();
			node.setEui64(uid64);
			getCoordinator().addNode(node);
		} else {

		}

	}

	/*private void sendCommand(String string) {
		communication.Send(string);
	}*/

	// nodes management
	public void DisplayProductInfo() {

		communication.Send("ATI");

	}

	public void ScanNetwork(byte hopsToList) {

		communication.Send("AT+SN:" + String.format("%02d", hopsToList));

	}

	public void FindSourceRouteToRemoteDevice(String uid64) {

		communication.Send("AT+FNDSR:" + uid64);

	}

	public void SoftwareReset() {

		communication.Send("ATZ");

	}

	public void RestoreFactoryDefaults() {

		communication.Send("AT&F");

	}

	public Communication getCommunication() {

		return communication;
	}

	public void setCommunication(Communication communication) {

		this.communication = communication;
	}

	public void ReadRegisterLocally(Register register) {

		communication.Send("ATS" + register.getValue() + "?");

	}

	public void WriteRegisterLocally(Register register, int value) {

		communication.Send("ATS" + register.getValue() + "="
				+ String.format("%02d", value));

	}

	public void ReadRegisterRemotely(String uid64, Register register) {

		communication.Send("ATREMS:" + uid64 + "," + register.getValue() + "?");

	}

	public void WriteRegisterRemotely(String uid64, Register register, int value) {

		communication.Send("ATREMS:" + uid64 + "," + register.getValue() + "="
				+ String.format("%04d", value));

	}

	public void WriteProtectedRegisterRemotely(ProtectedRegister register,
			String uid64, int value, String password) {

		communication.Send("ATREMS:" + uid64 + "," + register.getValue() + "="
				+ String.format("%04d", value) + ":" + password);
	}

	public void WriteProtectedRegisterLocally(
			ProtectedRegister protectedRegister, int value, String password) {

		communication.Send("ATS" + protectedRegister.getValue() + "="
				+ String.format("%02d", value) + ":" + password);

	}

	public void WriteToAllRegisterRemotely(BroadcastType broadcastType,
			Register register, int value) {

		communication.Send("ATSALL:" + broadcastType.getValue() + ","
				+ register.getValue() + "=" + String.format("%04d", value));
	}

	public void WriteToAllRegisterRemotely(BroadcastType broadcastType,
			ProtectedRegister protectedRegister, int value, String password) {

		communication.Send("ATSALL:" + broadcastType.getValue() + ","
				+ protectedRegister.getValue() + "="
				+ String.format("%04d", value) + ":" + password);
	}

	public void DisplayAllRegistersLocally() {
		communication.Send("AT+TOKDUMP");
	}

	public void ScanTheEnergyOfAllChannels() {
		communication.Send("AT+ESCAN");
	}

	public void ScanForActivePANs() {
		communication.Send("AT+PANSCAN");
	}

	public void EstablishPersonalAreaNetwork() {
		communication.Send("AT+EN");
	}

	public void JoinNetwork() {
		communication.Send("AT+JN");
	}

	public void JoinSpecificPAN(byte channel, PANidType panid, String id) {

		if (panid == PANidType.Extended && id.length() != 16) {
				throw new IllegalArgumentException("Invalid id lenght");

		} else if (panid == PANidType.Short && id.length() != 4) {
				throw new IllegalArgumentException("Invalid id lenght");
		}

		communication.Send("AT+JPAN:" + String.format("%02d", channel) + "," + id);
	}

	public void SilentJoin(byte channel, String uid64,
			String networkManagerNodeId, byte updateId) {

		if (networkManagerNodeId.length() != 16)
			throw new IllegalArgumentException("Invalid nodeId lenght");

		communication.Send("AT+SJN:" + String.format("%02d", channel) + "," + uid64
				+ "," + String.format("%02d", updateId));
	}

	public void DisassociateLocalDeviceFromPAN() {
		communication.Send("AT+DASSL");
	}

	public void DisassociateRemoteNodeFromPAN(String uid64) {
		communication.Send("AT+DASSL:" + uid64);
	}

	public void DisplayNetworkInformation() {
		communication.Send("AT+N?");
	}

	public void DisplayNeighbourTable(byte lqiTableStartIndex, String address) {
		
		communication.Send("AT+NTABLE:" + String.format("%02d", lqiTableStartIndex)
				+ "," + address);
	}
	
	public Coordinator getCoordinator() {
		return coordinator;
	}

	private void setCoordinator(Coordinator coordinator) {
		this.coordinator = coordinator;
	}

}
